﻿// Author: Wilfred Pinto
// Website: http://projectsilverlight.blogspot.com

using SimpleViewer_SL.code;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml;

namespace SimpleViewer_SL
{
    /// <summary>
    /// Contains all controls that are necessary for the rendering
    /// of the SimpleViewer-SL viewer
    /// </summary>
    [Obsolete("Used for documentation of namespace in Sandcastle Help File Builder", true)]
    internal class NamespaceDoc { }

    /// <summary>
    /// Implements the main layout
    /// </summary>
    public partial class Page : UserControl
    {
        Photo _photo = null;
        Thumbnails _thumbnails = null;
        int _photoIndex = -1;
        int _thumbnailsIndex = -1;

        /// <summary>
        /// Gets or sets the settings
        /// </summary>
        public GallerySettings Settings { get; set; }

        /// <summary>
        /// Initializes a new instance of the <c>Page</c> class
        /// </summary>
        public Page()
        {
            Settings = new GallerySettings();
            InitializeComponent();

            try
            {
                // Download the gallery.xml file
                WebClient downloader = new WebClient();
                Uri settingsUri;
                Uri.TryCreate(App.Current.Host.Source, ((App)Application.Current).Settings.XmlDataPath, out settingsUri);
                downloader.DownloadStringAsync(settingsUri, settingsUri.ToString());

                // On download completion delegate processing to the GalleryXml_DownloadStringCompleted method
                downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(GalleryXml_DownloadStringCompleted);
            }
            catch (Exception e)
            {
                // TODO: In case of any failure while downloading the gallery.xml file
                // an appropriate error message should be shown
                HtmlPage.Window.Alert("Page:" + e.Message);
            }

            // Capture the SizeChanged event to scale the photo
            // and thumbnails control appropriately
            this.SizeChanged += (sender, e) =>
            {
                // Output.Text = e.NewSize.ToString();
                if (_photo != null)
                {
                    // Remove the photo control so that it can be created
                    // later taking the new dimensions into account
                    LayoutPhoto.Children.Remove(_photo);
                }
                if (_thumbnails != null)
                {
                    AdjustLayout();
                    AddPhotoWindow(true);
                }
            };

            // Capture the Keydown event and delegate it to the thumbnails control
            KeyDown += delegate(object sender, KeyEventArgs e)
            {
                if (_thumbnails != null)
                    _thumbnails.KeyboardHandler(sender, e);
            };
        }

        /// <summary>
        /// Handles the successful download of the gallery.xml file
        /// </summary>
        /// <param name="sender">The source of the event</param>
        /// <param name="e">A System.Net.DownloadStringCompletedEventArgs that contains event data</param>
        protected void GalleryXml_DownloadStringCompleted(Object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                // So that we can handle the error in the exception block
                if (e.Error != null)
                    throw e.Error;

                using (XmlReader settingsXmlReader = XmlReader.Create(new StringReader(e.Result)))
                {
                    // Parse the gallery.xml file into the Settings object
                    Settings.ParseSettingsXmlFile(settingsXmlReader);
                }

                // The layout can be created after the gallery.xml file has been
                // downloaded and parsed successfully
                CreateLayout();
            }
            // Trap the WebException since it is thrown if the application is not
            // deployed on a webserver or if the file does not exist on the web server
            catch (System.Net.WebException exception)
            {
                String err = "Could not download the settings file: \n    " + e.UserState.ToString() + "\n";

                if ((exception.InnerException as System.NotSupportedException) != null)
                {
                    // Comes here if application is not deployed on web server
                    err += "\nPlease ensure that this application is deployed on a web server!";
                }
                else if ((exception.InnerException as System.Net.WebException) != null)
                {
                    // Comes here if file does not exist on web server
                    err += "\nPlease ensure that this file exists!";
                }
                else
                {
                    // TODO: In case of any failure while downloading the gallery.xml file
                    // an appropriate error message should be shown
                    err += exception.ToString();
                }

                HtmlPage.Window.Alert(err);
            }
            catch (Exception exception)
            {
                // TODO: In case of any failure while downloading the gallery.xml file
                // an appropriate error message should be shown
                HtmlPage.Window.Alert("GalleryXml_DownloadStringCompleted:" + exception.ToString());
            }
        }

        /// <summary>
        /// Creates the main layout
        /// </summary>
        protected void CreateLayout()
        {
            if (!String.IsNullOrEmpty(Settings.BackgroundImagePath))
            {
                // Set the background of the entire layout
                LayoutRoot.Background = new ImageBrush { ImageSource = new BitmapImage(new Uri(Settings.BackgroundImagePath, UriKind.Relative)), Stretch = Stretch.Fill };
            }

            if (Settings.ImageAndThumbBandBackgroundColor != Settings.NoColor)
            {
                // Set the background of the photo and thumbnails control
                LayoutViewer.Background = new SolidColorBrush(Settings.ImageAndThumbBandBackgroundColor);
            }
            else
            {
                if (Settings.ImageBackgroundColor != Settings.NoColor)
                {
                    // Set the background of the photo control only
                    LayoutPhoto.Background = new SolidColorBrush(Settings.ImageBackgroundColor);
                }
                if (Settings.ThumbBackgroundColor != Settings.NoColor)
                {
                    // Set the background of the thumbnails control only
                    LayoutThumbnails.Background = new SolidColorBrush(Settings.ThumbBackgroundColor);
                }
            }

            // Instantiate the photo and thumbnails control
            if (_thumbnails == null) _thumbnails = new Thumbnails(this);
            if (_photo == null) _photo = new Photo(this);

            // If the thumbnails are positioned to the left or right of the photo image
            if (Settings.NavPosition == NavPosition.Right || Settings.NavPosition == NavPosition.Left)
            {
                // Create four columns - 2 for margins and 1 each for the photo and thumbnails control
                LayoutViewer.ColumnDefinitions.Add(new ColumnDefinition());
                LayoutViewer.ColumnDefinitions.Add(new ColumnDefinition());
                LayoutViewer.ColumnDefinitions.Add(new ColumnDefinition());
                LayoutViewer.ColumnDefinitions.Add(new ColumnDefinition());

                // Calculate and set the column index of the photo and thumbnails control
                // if Settings.HAlign is
                //   Left   - photo column index is 0 and thumbnails column index is 1 if NavPosition is Right 
                //   Center - photo column index is 1 and thumbnails column index is 2 if NavPosition is Right 
                //   Right  - photo column index is 2 and thumbnails column index is 3 if NavPosition is Right 
                int HAlignIndex = (Settings.HAlign == Align.Left) ? 0 : (Settings.HAlign == Align.Center) ? 1 : 2;
                _photoIndex = HAlignIndex + (Settings.NavPosition == NavPosition.Right ? 0 : 1);
                _thumbnailsIndex = HAlignIndex + (Settings.NavPosition == NavPosition.Right ? 1 : 0);

                LayoutPhoto.SetValue(Grid.ColumnProperty, _photoIndex);
                LayoutThumbnails.SetValue(Grid.ColumnProperty, _thumbnailsIndex);

                // Set the vertical alignment of the viewer layout
                LayoutViewer.VerticalAlignment = (Settings.VAlign == Align.Top) ? VerticalAlignment.Top : (Settings.VAlign == Align.Center) ? VerticalAlignment.Center : VerticalAlignment.Bottom;
            }
            // If the thumbnails are positioned to the top or bottom of the photo image
            else if (Settings.NavPosition == NavPosition.Top || Settings.NavPosition == NavPosition.Bottom)
            {
                // Create four rows - 2 for margins and 1 each for the photo and thumbnails control
                LayoutViewer.RowDefinitions.Add(new RowDefinition());
                LayoutViewer.RowDefinitions.Add(new RowDefinition());
                LayoutViewer.RowDefinitions.Add(new RowDefinition());
                LayoutViewer.RowDefinitions.Add(new RowDefinition());

                // Calculate and set the row index of the photo and thumbnails control
                // if Settings.VAlign is
                //   Top    - photo row index is 0 and thumbnails row index is 1 if NavPosition is Bottom 
                //   Center - photo row index is 1 and thumbnails row index is 2 if NavPosition is Bottom 
                //   Bottom - photo row index is 2 and thumbnails row index is 3 if NavPosition is Bottom 
                int VAlignIndex = (Settings.VAlign == Align.Top) ? 0 : (Settings.VAlign == Align.Center) ? 1 : 2;
                _photoIndex = VAlignIndex + (Settings.NavPosition == NavPosition.Bottom ? 0 : 1);
                _thumbnailsIndex = VAlignIndex + (Settings.NavPosition == NavPosition.Bottom ? 1 : 0);

                LayoutPhoto.SetValue(Grid.RowProperty, _photoIndex);
                LayoutThumbnails.SetValue(Grid.RowProperty, _thumbnailsIndex);

                // Set the horizontal alignment of the viewer layout
                LayoutViewer.HorizontalAlignment = (Settings.HAlign == Align.Left) ? HorizontalAlignment.Left : (Settings.VAlign == Align.Center) ? HorizontalAlignment.Center : HorizontalAlignment.Right;
            }

            AdjustLayout();

            // Add the Thumbnails and photo controls
            AddThumbnailWindow();
            AddPhotoWindow(false);
        }

        /// <summary>
        /// Adjust the layout by assigning appropriate width and height to the
        /// grid rows and/or columns
        /// </summary>
        /// <remarks>
        /// This logic has been separated from the <see cref="CreateLayout">CreateLayout</see>
        /// since it is required when resizing the main layout
        /// </remarks>
        protected void AdjustLayout()
        {
            // Only if there is a valid thumbnails and photo control already created
            if (_photo != null && _thumbnails != null && _photoIndex >= 0 && _thumbnailsIndex >= 0)
            {
                // if it's a left right view
                if (LayoutViewer.ColumnDefinitions.Count > 0)
                {
                    // if the combined width of the thumbnails and photo window 
                    // is more than the width of the container
                    if (_photo.ControlWidth + _thumbnails.ControlWidth > Application.Current.Host.Content.ActualWidth)
                    {
                        // first set all the columns to auto width
                        // the side effect of specifying star widths for the margins is that
                        // they will occupy some space but we barely have space for the photo
                        // and thumbnails control
                        for (int i = 0; i < LayoutViewer.ColumnDefinitions.Count; i++)
                        {
                            LayoutViewer.ColumnDefinitions[i].Width = new GridLength(1, GridUnitType.Auto);
                        }

                        // we can compromise on the photo width but the thumbnails width should be preserved
                        LayoutViewer.ColumnDefinitions[_photoIndex].Width = new GridLength(1, GridUnitType.Star);
                        LayoutViewer.ColumnDefinitions[_photoIndex].MaxWidth = _photo.ControlWidth;
                    }
                    // if the combined width of the thumbnails and photo window 
                    // is less than or equal to the width of the container
                    else
                    {
                        // first set all the columns to star width
                        for (int i = 0; i < LayoutViewer.ColumnDefinitions.Count; i++)
                        {
                            LayoutViewer.ColumnDefinitions[i].Width = new GridLength(1, GridUnitType.Star);
                        }

                        // set the width of the photo column to the width of the photo control
                        LayoutViewer.ColumnDefinitions[_photoIndex].Width = new GridLength(_photo.ControlWidth);
                    }

                    // set the width of the thumbnails column to the width of the thumbnails control
                    LayoutViewer.ColumnDefinitions[_thumbnailsIndex].Width = new GridLength(_thumbnails.ControlWidth);
                }
                // if it's a top down view
                else if (LayoutViewer.RowDefinitions.Count > 0)
                {
                    // if the combined height of the thumbnails and photo window 
                    // is more than the height of the container
                    if (_photo.ControlHeight + _thumbnails.ControlHeight > Application.Current.Host.Content.ActualHeight)
                    {
                        // first set all the rows to auto height
                        // the side effect of specifying star heights for the margins is that
                        // they will occupy some space but we barely have space for the photo
                        // and thumbnails control
                        for (int i = 0; i < LayoutViewer.RowDefinitions.Count; i++)
                        {
                            LayoutViewer.RowDefinitions[i].Height = new GridLength(1, GridUnitType.Auto);
                        }

                        // we can compromise on the photo height but the thumbnails height should be preserved
                        LayoutViewer.RowDefinitions[_photoIndex].Height = new GridLength(1, GridUnitType.Star);
                        LayoutViewer.RowDefinitions[_photoIndex].MaxHeight = _photo.ControlHeight;
                    }
                    // if the combined height of the thumbnails and photo window 
                    // is less than or equal to the height of the container
                    else
                    {
                        // first set all the rows to star height
                        for (int i = 0; i < LayoutViewer.RowDefinitions.Count; i++)
                        {
                            LayoutViewer.RowDefinitions[i].Height = new GridLength(1, GridUnitType.Star);
                        }

                        // set the height of the photo row to the height of the photo control
                        LayoutViewer.RowDefinitions[_photoIndex].Height = new GridLength(_thumbnails.ControlHeight);
                    }

                    // set the height of the thumbnails row to the height of the thumbnails control
                    LayoutViewer.RowDefinitions[_thumbnailsIndex].Height = new GridLength(_thumbnails.ControlHeight);
                }
            }
        }

        /// <summary>
        /// Adds the thumbnails window to the main layout
        /// </summary>
        protected void AddThumbnailWindow()
        {
            if (_thumbnails != null)
            {
                // Add the thumbnails control
                LayoutThumbnails.Children.Add(_thumbnails);

                // Select the user specified thumbnail
                _thumbnails.SelectedThumbnailIndex = ((App)Application.Current).Settings.FirstImageIndex;

                // Handle the thumbnails PropertyChanged event to display the corresponding
                // photo when user navigates the thumbnails
                _thumbnails.PropertyChanged += (sender, e) =>
                {
                    if (_photo != null && e.PropertyName.Equals("SelectedThumbnailIndex"))
                        _photo.SelectedPhotoIndex = _thumbnails.SelectedThumbnailIndex;
                };
            }
        }

        /// <summary>
        /// Adds the photo window to the main layout
        /// </summary>
        /// <param name="bCreateWindow">Whether the window should be created or not</param>
        protected void AddPhotoWindow(bool bCreateWindow)
        {
            int selectedPhotoIndex = 0;

            if (bCreateWindow)
            {
                // Preserve the last displayed photo when creating a new photo control
                selectedPhotoIndex = (_photo != null) ? _photo.SelectedPhotoIndex : 0;

                // Create a new photo control
                _photo = new Photo(this);
            }

            _photo.SelectedPhotoIndex = selectedPhotoIndex;

            // Add the photo control
            LayoutPhoto.Children.Add(_photo);

            // Handle the photos PropertyChanged event to highlight the appropriate
            // thumbnail when user navigates the photos through the photo window
            _photo.PropertyChanged += (sender, e) =>
            {
                if (_thumbnails != null && e.PropertyName.Equals("SelectedPhotoIndex"))
                    _thumbnails.SelectedThumbnailIndex = ((Photo)sender).SelectedPhotoIndex;
            };
        }
    }
}
